import socket
import sys
import threading
from typing import Optional
import socket
import time

def get_public_ipv6() -> Optional[str]:
    """获取本地240开头的公网IPv6地址（排除链路本地地址）"""
    try:
        # 获取所有网络接口的IPv6地址
        for addr_info in socket.getaddrinfo('', None, socket.AF_INET6):
            ip = addr_info[4][0]
            # 排除链路本地地址(fe80::)和环回地址(::1)，匹配240开头的公网地址
            if not ip.startswith(('fe80:', '::1')) and ip.startswith('240'):
                return ip
        return None
    except Exception as e:
        print(f"获取IPv6地址失败: {str(e)}")
        return None

def udp_server(host='::', port=1976):
    # Create UDP socket with IPv6 support
    with socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) as sock:
        # Allow address reuse if the port is still in TIME_WAIT state
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        
        # Bind to all IPv6 interfaces on the specified port
        sock.bind((host, port))
        print(f"IPv6 UDP server listening on [{host}]:{port}")
        
        while True:
            # Receive data from client (buffer size 1024 bytes)
            data, client_addr = sock.recvfrom(1024)
            client_ip, client_port = client_addr[0], client_addr[1]
            print(f"Received from [{client_ip}]:{client_port}: {data.decode('utf-8')}")
            
            # Send the data back to the client (ping-pong)
            sock.sendto(data, client_addr)
            print(f"Sent back to [{client_ip}]:{client_port}")

def udp_client(server_ip='::1', server_port=5005, message="Hello IPv6 UDP!"):
    while True:
        time.sleep(15)
        with socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) as sock:
            # Set timeout for response (5 seconds)
            sock.settimeout(5)
        
            try:
                # Send message to server
                start_time = time.time()
                sock.sendto(message.encode('utf-8'), (server_ip, server_port))
                print(f"Sent to [{server_ip}]:{server_port}: {message}")
            
                # Receive response
                data, server_addr = sock.recvfrom(1024)
                rtt = (time.time() - start_time) * 1000  # Round-trip time in milliseconds
                print(f"Received from [{server_addr[0]}]:{server_addr[1]}: {data.decode('utf-8')}")
                print(f"RTT: {rtt:.2f} ms")
            
            except socket.timeout:
                print("Error: No response from server (timeout)")
            except Exception as e:
                print(f"Error: {e}")

def main():
    # 检查是否有命令行参数
    if len(sys.argv) > 1:
        print("错误: 不支持命令行参数，本程序仅在无参数时运行")
        sys.exit(1)
    
    # 获取本地公网IPv6地址
    local_ipv6 = get_public_ipv6()
    if not local_ipv6:
        print("错误: 未找到240开头的公网IPv6地址，请确保网络已启用IPv6")
        sys.exit(1)
    
    # 目标服务器配置
    TARGET_IP = "240e:33d:16:25a0:fc82:e870:9098:19e7"
    TARGET_PORT = 1976
    
    # 启动UDP服务器线程（后台运行）
    server_thread = threading.Thread(target=udp_server, args=["::", 1976], daemon=True)
    server_thread.start()
    
    # 发送UDP数据到目标服务器
    client_thread = threading.Thread(target=udp_client, args=[TARGET_IP, TARGET_PORT, local_ipv6], daemon=True)
    #udp_client(TARGET_IP, TARGET_PORT, local_ipv6)
    client_thread.start()
    
    # 保持主线程运行，等待服务器接收数据
    try:
        while True:
            pass
    except KeyboardInterrupt:
        print("\n程序已手动终止")
        sys.exit(0)

if __name__ == "__main__":
    main()